using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using HybridCLR.Editor;
using ProtoBuf;
using ProtoBuf.Meta;
using UnityEditor;
using UnityEngine;

public static class CreateTypeModel
{
    [MenuItem("HybridCLR/Build/生成协议模型(protobuf-model)", false, -1000)]
    private static void RebuildProtobufModelForProject()
    {
        RuntimeTypeModel typeModel = GetModel(out string typeNames);
        if (typeModel == null)
        {
            return;
        }
        
        string outputPath   = "Assets/StreamingAssets/protobuf-model.dll.bytes";
        
        typeModel.Compile("ProjectModel", "protobuf-model.dll");
        
        File.Copy("protobuf-model.dll", outputPath, true);
        File.Delete("protobuf-model.dll");
        
        AssetDatabase.Refresh();
        
        Debug.Log("[COPY] protobuf-model.dll -> " + outputPath);
        Debug.Log("为以下类型重建protobuf-model.dll\r\n" + typeNames);
    }

    private static RuntimeTypeModel GetModel(out string typeNames)
    {
        var types         = GetProtocalTypeList();
        var typeModel     = RuntimeTypeModel.Create();
        var stringBuilder = new StringBuilder();
        var list          = new List<Type>();
        foreach (var t in types)
        {
            var contract = t.GetCustomAttributes(typeof(ProtoContractAttribute), false);
            if (contract.Length > 0 && !list.Contains(t))
            {
                typeModel.Add(t, true);
                stringBuilder.Append(t.ToString());
                stringBuilder.Append("\r\n");
                list.Add(t);
            }
        }
        typeNames = stringBuilder.ToString();
        return typeModel;
    }


    private static List<Type> GetProtocalTypeList()
    {
        var baseType = typeof(IExtensible);
        var ass = AppDomain.CurrentDomain.GetAssemblies();
        var types = ass.SelectMany(s => s.GetTypes());
        var myTypes = types.Where(p => baseType.IsAssignableFrom(p) && !p.IsAbstract);
        var list = myTypes.ToList();

        return list;
    }
}
